#ifdef WITH_OPENGL
#include "renderer_opengl.h"

// this list is currently way to big
#include "renderer.h"
#include "matrix.h"
#include "context_opengl.h"
#include "mesh.h"
#include "effect.h"
#include "camera.h"
#include "vertex.h"
#include "vector3.h"
#include "shader_catalog_cg_opengl.h"
#include "opengl.h"
#include "string_util.h"
#include "render_control_opengl.h"
#include "refc_ptr.h"

using namespace krryn::core;
using namespace krryn::system_imp;
using namespace krryn::system;
using namespace krryn::scene;
using namespace krryn::math;

renderer_opengl::renderer_opengl() : m_Activate(0), m_Camera(0){
	// determine supported extensions and load them
	m_Extensions = explode((char*)glGetString(GL_EXTENSIONS), " ");

	std::vector<std::string> l_Failed 
		= opengl_helper::load_extensions(m_Extensions);

	/// TODO: we should check / assert if the user doesn't
	///  have extensions we depend upon (currently only VBO / multi-texture)

	std::cout 
		<< "OpenGL version: " 
		<< (char*)glGetString(GL_VERSION)
		<< " (" << (char*)glGetString(GL_RENDERER) << ")"
		<< std::endl;

#ifdef _DEBUG
	std::cout
		<< "OpenGL extensions supported: "
		<< std::endl
		<< " - " 
		<< implode(m_Extensions, "\n - ") 
		<< std::endl;

	if(!l_Failed.empty()){
		std::cout 
			<< "Notice: failed to load the following function pointers: "
			<< std::endl
			<< " - " << implode(l_Failed, "\n - ")
			<< std::endl;
	}
#endif

	glMatrixMode(GL_PROJECTION);

	// math::matrix is row-major so we need the transpose
	matrix m = matrix::create_perspective_projection(1.f, 100.f, 1, .75);
	glLoadMatrixf(m.transpose().cell);

	glMatrixMode(GL_MODELVIEW);
	glShadeModel(GL_SMOOTH);

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
}

void renderer_opengl::begin_scene(){
	if(m_Activate != 0)
		m_Activate->activate();

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	/*if(m_Camera){
		m_MatrixStack.push();
		m_MatrixStack.concatenate(m_Camera->view_matrix())
	}*/

	m_MatrixStack.push();
}

void renderer_opengl::end_scene(){
	m_MatrixStack.pop();

	if(m_Activate)
		m_Activate->m_Control.swap_buffers();
}

void renderer_opengl::draw(renderable &a_Mesh, const matrix &a_Transformation){
	typedef scene::renderable::effect_list_t effect_list_t;

	const effect_list_t &l_Effects = a_Mesh.effects();

	m_MatrixStack.push();
	m_MatrixStack.concatenate(a_Transformation);

	glLoadMatrixf(m_MatrixStack.top().transpose().cell);

	for(effect_list_t::const_iterator i = l_Effects.begin(); i != l_Effects.end(); i++){
		(*i)->enable();
	}

	a_Mesh.draw();

	for(effect_list_t::const_iterator i = l_Effects.begin(); i != l_Effects.end(); i++){
		(*i)->disable();
	}

	m_MatrixStack.pop();
}


#endif

//#ifdef WITH_OPENGL
//#include "renderer_opengl.h"
//#include "mesh.h"
//#include "jobs.h"
//#include "effect.h"
//#include "camera.h"
//#include "matrix.h"
//#include "vertex.h"
//#include "vector3.h"
//#include "shader_catalog_cg_opengl.h"
//#include "opengl.h"
//#include "string_util.h"
//#include "vertex_buffer_opengl.h"
//#include "index_buffer_opengl.h"
//#include "refc_ptr.h"
//
//#include <iostream>
//
//using namespace krryn;
//using namespace krryn::core;
//using namespace krryn::system_imp;
//using namespace krryn::system;
//using namespace krryn::scene;
//using namespace krryn::math;
//
//#define BUFFER_OFFSET(i) ((char*)NULL + (i))
//
//renderer_opengl::renderer_opengl(job_manager *a_Manager, const viewport_settings &a_Viewport) 
//: renderer(a_Manager), 
//  m_Viewport(a_Viewport), 
//  m_ProjectionMatrix(matrix::create_perspective_projection(1.f, 1000.f, 1, 0.75)),
//  m_Camera(0)
//{
//}
//
//renderer_opengl::~renderer_opengl(){
//}
//
//view::shader_catalog* renderer_opengl::get_shader_catalog(){
//	if(m_Catalog == 0){
//		m_Catalog = new shader_catalog_cg_opengl();
//	}
//
//	return m_Catalog;
//}
//
//void renderer_opengl::set_projection_matrix(const math::matrix &a_ProjectionMatrix){
//	m_ProjectionMatrix = a_ProjectionMatrix;
//}
//
//void renderer_opengl::set_camera(view::camera *a_Camera){
//	m_Camera = a_Camera;
//}
//
//void renderer_opengl::setup(){
//	m_Extensions.swap(explode((char*)glGetString(GL_EXTENSIONS), " "));
//
//	std::cout 
//		<< "opengl version: " 
//		<< (char*)glGetString(GL_VERSION)
//		<< " (" << (char*)glGetString(GL_RENDERER) << ")"
//		<< std::endl
//#ifdef _DEBUG
//		<< "opengl extensions supported: "
//		<< std::endl
//		<< " - " 
//		<< implode(m_Extensions, "\n - ") 
//		<< std::endl
//#endif
//		; // notice semi colon!
//
//	std::vector<std::string> l_Failed = opengl_helper::load_extensions(m_Extensions);
//
//#ifdef _DEBUG
//	if(!l_Failed.empty()){
//		std::cout 
//			<< "notice: failed to load the following function pointers: "
//			<< std::endl
//			<< " - " << implode(l_Failed, "\n - ")
//			<< std::endl;
//	}
//#endif
//
//	glMatrixMode(GL_PROJECTION);
//	glLoadIdentity();
//
//	// math::matrix is row-major so we can do this
//	glLoadMatrixf(m_ProjectionMatrix.cell);
//
//	glMatrixMode(GL_MODELVIEW);
//	glLoadIdentity();
//
//	glEnable(GL_DEPTH_TEST);
//	glDepthFunc(GL_LESS);
//
//	// TODO: remove dummy light
//	glEnable(GL_LIGHTING);
//	glEnable(GL_LIGHT0);
//	float p[] = {0, 0, 2};
//	float c1[] = {1, 1, 1, 1};
//	float c2[] = {1, 1, 1, 1};
//	glLightfv(GL_LIGHT0, GL_POSITION, p);
//	glLightfv(GL_LIGHT0, GL_AMBIENT, c1);
//	glLightfv(GL_LIGHT0, GL_DIFFUSE, c2);
//}
//
//void renderer_opengl::tear_down(){
//}
//
//void renderer_opengl::begin_scene(){
//	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//
//	glMatrixMode(GL_MODELVIEW);
//	glLoadIdentity();
//
//	if(m_Camera){
//		matrix l_ViewMatrix = m_Camera->view_matrix();
//		glLoadMatrixf(l_ViewMatrix.cell);
//	}
//
//	glPushMatrix();
//	glEnableClientState(GL_VERTEX_ARRAY);
//	glEnableClientState(GL_COLOR_ARRAY);
//	glEnableClientState(GL_NORMAL_ARRAY);
//	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//}
//
//void renderer_opengl::draw(scene::mesh *a_Mesh, const math::matrix &a_Transformation){
//	typedef scene::mesh::effect_list_t effect_list_t;
//
//	if(!a_Mesh)
//		return;
//
//	const effect_list_t &l_Effects = a_Mesh->get_effects();
//
//	glPushMatrix();
//	glMultMatrixf(a_Transformation.cell);
//
//	/*vertex_buffer_opengl *l_VertexBuffer
//		= (vertex_buffer_opengl *)a_Mesh->get_vertex_buffer().get();
//
//	index_buffer::ptr l_IndexBuffer
//		= a_Mesh->get_index_buffer();*/
//
//	//l_VertexBuffer->lock();
//	//l_IndexBuffer->lock();
//
//	for(effect_list_t::const_iterator i = l_Effects.begin(); i != l_Effects.end(); i++){
//		(*i)->enable();
//	}
//
//	//glBegin(GL_TRIANGLES);		// Drawing Using Triangles
//	//glVertex3f( 0.0f, 15.0f, -100.0f);		// Top
//	//glVertex3f(-15.0f,-15.0f, -100.0f);		// Bottom Left
//	//glVertex3f( 15.0f,-15.0f, -100.0f);		// Bottom Right
// //   glEnd();	
//
//	for(effect_list_t::const_iterator i = l_Effects.begin(); i != l_Effects.end(); i++){
//		(*i)->disable();
//	}
//
////	l_VertexBuffer->unlock();
//	//l_IndexBuffer->unlock();
//
//	glPopMatrix();
//}
//
//vertex_buffer::ptr renderer_opengl::create_vertex_buffer(krryn::scene::usage_type a_Usage, size_t a_NumVertices){
//	//return vertex_buffer_opengl<vertex::description_type>::ptr(
//	//	new vertex_buffer_opengl<vertex::description_type>(a_Usage, a_NumVertices)
//	//).as<vertex_buffer>();
//}
//
//index_buffer::ptr renderer_opengl::create_index_buffer(krryn::scene::usage_type a_Usage, size_t a_NumIndices){
////	return index_buffer_opengl::ptr(
////		new index_buffer_opengl(a_Usage, a_NumIndices)
////	).as<index_buffer>();
//	return 0;
//}
//
//void renderer_opengl::end_scene(){
//	glDisableClientState(GL_VERTEX_ARRAY);
//	glDisableClientState(GL_COLOR_ARRAY);
//	glDisableClientState(GL_NORMAL_ARRAY);
//	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
//
//	glPopMatrix();
//	glFinish();
//}
//
//#undef BUFFER_OFFSET
//#endif